<!-- 简易结构树 -->

<template>
  <div :class="divClass" :style="divStyle">
    <!-- 顶部插槽 -->
    <div :class="`${className}-top`">
      <slot name="top" />
    </div>

    <!-- 筛选框 -->
    <el-input v-if="!noFilter" v-model.trim="filter" :placeholder="filterTip" clearable>
      <template v-if="filterPrefix" #prefix>
        <i class="el-input__icon" :class="filterPrefix" />
      </template>
      <template v-if="filterSuffix" #suffix>
        <i class="el-input__icon" :class="filterSuffix" />
      </template>
    </el-input>

    <!-- 结构树 -->
    <EasyScroll :wide="wide" :style="treeStyle" hasX>
      <el-tree
        ref="tree"
        v-bind="config"
        @node-click="nodeClick"
        @node-expand="nodeExpand"
        @node-collapse="nodeCollapse"
      >
        <template #default="{ node, data }">
          <div>
            <slot :data="data" :node="node" :nodeClass="getNodeClass(data)">
              <span :class="getNodeClass(data)">{{ node.label }}</span>
            </slot>
            <BtnReset v-if="!disabled && hasReset && chosenId === node.key" v-bind="resetBtn" @click="nodeClick({})" />
          </div>
        </template>
      </el-tree>
    </EasyScroll>

    <!-- 底部插槽 -->
    <div :class="`${className}-bottom`">
      <slot name="bottom" />
    </div>
  </div>
</template>

<script>
// ============================== 导入依赖 ============================== //

import CORE from '@/CORE'
import mixPath from '../mixPath'
import UTIL from './UTIL'
import WebForm from '../WebForm'

const name = 'EasyTree'

// ============================== 导出组件 ============================== //

export default {
  /**
   * 名称定义 (实际使用名称)
   */
  name,

  /**
   * 混入列表 (配置选项合并)
   */
  mixins: [mixPath],

  /**
   * 组件导入 (Abc.vue + Abc/index.vue)
   */
  ...CORE.components(require.context('./', true, /vue$/)),

  /**
   * 属性注册 (抽取以便查阅)
   */
  props: CORE.WEB[name],

  /**
   * 模型绑定
   */
  model: {
    prop: 'chosenId', // 与 props 里的名称一致
    event: 'idChange', // 回传调用的事件名称
  },

  /**
   * 状态数据 (函数返回对象)
   */
  data() {
    return {
      filter: '', // 过滤值
    }
  },

  /**
   * 计算属性 (慎用箭头函数)
   */
  computed: {
    /**
     * 尺寸
     */
    size: WebForm.computed.size,

    /**
     * 属性映射
     */
    props() {
      const { field, state } = this
      const treeField = field || state.TREE_FIELD || []
      const [children = 'children', id = 'id', label = 'name'] = treeField
      return { children, id, label, disabled: 'disabled' }
    },

    /**
     * 表单配置
     */
    config() {
      const { elProps, tree, state, props, expandRoot } = this
      const defaultExpandedKeys = expandRoot ? tree.map((item) => item[props.id]) : null
      return {
        ...elProps,
        data: tree || state.tree,
        nodeKey: props.id,
        props,
        defaultExpandAll: this.expandAll,
        expandOnClickNode: this.expandOnClick,
        filterNodeMethod: this.filterNode,
        defaultExpandedKeys,
      }
    },

    /**
     * 路径名称的映射
     */
    namesMap() {
      const { tree, state, props } = this
      const namesMap = {}
      UTIL.setNamesMap(namesMap, tree || state.tree, props)
      return namesMap
    },

    /**
     * 默认 ID
     */
    initId() {
      const { chosenId, config, init, initRoot, initFirst, namesMap } = this
      if (chosenId) return chosenId // 已有选中
      if (!config.data.length) return '' // 结构树为空
      if (init && namesMap[init]) return init // 有默认值
      if (initRoot) return config.data[0][config.nodeKey] // 默认根节点
      if (initFirst) { // 默认第一个叶子
        let first = config.data[0]
        while (!CORE.isEmpty(first[config.props.children])) first = first[config.props.children][0]
        return first[config.nodeKey]
      }
      return '' // 无选中
    },

    /**
     * 样式类
     */
    divClass() {
      const { className, size, noPadding } = this
      const sizeStr = size ? ` ${className}-${size}` : ''
      const paddingStr = noPadding ? ` ${className}-no-padding` : ''
      return `${className}${sizeStr}${paddingStr}`
    },

    /**
     * 样式对象
     */
    divStyle() {
      const { height, getSize } = this
      const style = {}
      if (height) style.height = getSize(height)
      return style
    },

    /**
     * 结构树样式对象
     */
    treeStyle() {
      const { treeHeight, getSize } = this
      const style = {}
      if (treeHeight) style.height = getSize(treeHeight)
      return style
    },
  },

  /**
   * 监听属性 (深度 deep 首次 immediate)
   */
  watch: {
    /**
     * 监听默认 ID
     */
    initId: {
      immediate: true,
      handler(id) {
        this.$emit('idChange', id)
      },
    },

    /**
     * 监听过滤值
     */
    filter(val) {
      this.$refs.tree.filter(val)
    },

    /**
     * 监听结构树
     */
    async 'config.data'() {
      await this.$nextTick()
      this.$refs.tree.filter(this.filter)
    },
  },

  /**
   * 本地方法 (轻量重要在前)
   */
  methods: {
    /**
     * 节点点击
     */
    nodeClick(data) {
      if (this.disabled || data.disabled) return

      const { props } = this
      this.$emit('idChange', data[props.id])
      this.$emit('change', data)
    },

    /**
     * 节点展开
     */
    nodeExpand(data) {
      this.$emit('expand', data)
      if (this.expandOnClick) this.nodeClick(data)
    },

    /**
     * 节点收缩
     */
    nodeCollapse(data) {
      this.$emit('collapse', data)
      if (this.expandOnClick) this.nodeClick(data)
    },

    /**
     * 过滤节点
     */
    filterNode(value, data) {
      if (!value) return true

      const { props, namesMap } = this
      const id = data[props.id]
      return !/->$/.test(namesMap[id]) && namesMap[id].includes(value) // 排除叶子名称为空的节点
    },

    /**
     * 获取节点样式类
     */
    getNodeClass(data) {
      const { disabled, props, chosenId, className } = this
      if (data.disabled) return `${className}-disabled`
      if (disabled && data[props.id] !== chosenId) return `${className}-disabled`
      if (data[props.id] === chosenId) return `${className}-chosen el-button--text`
      return null
    },
  },
}
</script>
